#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
#include "qemu/bitops.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/arm/primecell.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/fifo8.h"
#include "hw/i2c/i2c.h"
#include <string.h>

#define TYPE_HS0703_I2C "hs0703"
#define HS0703(obj) \
    OBJECT_CHECK(hs0703_state, (obj), TYPE_HS0703_I2C)

#ifdef DEBUG_HS0703
#define DPRINTF(_x ...) printf(_x)
#else
#define DPRINTF(_x ...)
#endif

#define RECV_FIFO_LENGTH         64

#define HS0703_DISABLE_SET_REG(i2c_status, target, value) \
{                                                             \
    do {                                                      \
        if ((i2c_status) == 0) {                              \
            (target) = (value);                               \
        }                                                     \
    } while (0);                                              \
}                                                             \

// flags of 0x10
#define I2C_FLAG_READ             0x100
#define I2C_FLAG_STOP             0x200

#define I2C_NEED_STOP(data)       (((data) & I2C_FLAG_STOP) ? true : false)

#define I2C_IS_READ(data)         (((data) & I2C_FLAG_READ) ? true : false)

/* I2C控制寄存器。注意：只在I2C被禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_CON		        0x0000
/* I2C访问Slave地址寄存器。注意：只在I2C被禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_TAR	            0x0004
/* I2C访问源设备地址寄存器。注意：只在I2C被禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_SAR		        0x0008
/* HS模式下Mater地址。注意：只在I2C被禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_HS_MADDR         0x000C
/* I2C数据通道寄存器 */
#define HS0703_DATA_CMD		    0x0010
/* 标准速度下的SCL时钟高电平时间寄存器。注意：只在I2C被禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_SS_SCL_HCNT	    0x0014
/* 标准速度下的SCL时钟低电平时间寄存器。注意：只在I2C禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_SS_SCL_LCNT	    0x0018
/* 快速速度下的SCL时钟高电平时间寄存器。注意：只在I2C禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_FS_SCL_HCNT	    0x001C
/* 快速速度下的SCL时钟低电平时间寄存器。I2C_FS_SCL_LCNT只在I2C禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_FS_SCL_LCNT	    0x0020
/* 高速模式下SCL时钟高电平时间配置寄存器注意：只在I2C禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_HS_SCL_HCNT	    0x0024
/* 高速模式下SCL时钟低电平时间配置寄存器注意：只在I2C禁止（即I2C_ENABLE[enable]为0）时才可配置 */
#define HS0703_HS_SCL_LCNT	    0x0028
/* I2C中断状态寄存器 */
#define HS0703_INTR_STAT	    0x002C
/* I2C中断屏蔽寄存器 */
#define HS0703_INTR_MASK        0x0030
/* I2C原始中断状态寄存器 */
#define HS0703_RAW_INTR_STAT    0x0034
/* RX_FIFO阈值寄存器 */
#define HS0703_RX_TL            0x0038
/* TX_FIFO阈值寄存器 */
#define HS0703_TX_TL            0x003C
/* I2C组合及独立中断清除寄存器 */
#define HS0703_CLR_INTR         0x0040
/* RX_UNDER中断清除寄存器 */
#define HS0703_CLR_RX_UNDER     0x0044
/* RX_OVER中断清除寄存器 */
#define HS0703_CLR_RX_OVER      0x0048
/* TX_OVER中断清除寄存器 */
#define HS0703_CLR_TX_OVER      0x004C
/* RD_REQ中断清除寄存器 */
#define HS0703_CLR_RD_REQ       0x0050
/* TX_ABRT中断清除寄存器 */
#define HS0703_CLR_TX_ABRT      0x0054
/* RX_DONE中断清除寄存器 */
#define HS0703_CLR_RX_DONE      0x0058
/* activity状态寄存器 */
#define HS0703_CLR_ACTIVITY     0x005C
/* STOP_DET中断清除寄存器 */
#define HS0703_CLR_STOP_DET     0x0060
/* START_DET中断清除寄存器 */
#define HS0703_CLR_START_DET    0x0064
/* General Call中断清除寄存器 */
#define HS0703_CLR_GEN_CALL     0x0068
/* I2C工作模式使能寄存器 */
#define HS0703_ENABLE           0x006C
/* I2C状态寄存器 */
#define HS0703_STATUS           0x0070
/* TX_FIFO中的数据个数指示寄存器 */
#define HS0703_TXFLR            0x0074
/* RX_FIFO中的数据个数指示寄存器 */
#define HS0703_RXFLR            0x0078
/* I2C_SDA_HOLD为SDA信号在SCL的下降沿后的hold延迟时间 */
#define HS0703_SDA_HOLD         0x007C
/* 发送失败中断源头寄存器。读I2C_CLR_INTR或I2C_CLR_TX_ABRT时，I2C_TX_ABRT_SOURCE清零 */
#define HS0703_TX_ABRT_SOURCE   0x0080
/* slave数据NACK产生控制寄存器 */
#define HS0703_SLV_DATA_ONLY    0x0084
/* I2C的DMA通道开启控制寄存器 */
#define HS0703_DMA_CR           0x0088
/* DMA操作阈值寄存器 */
#define HS0703_DMA_TDLR	        0x008C
/* DMA操作阈值寄存器 */
#define HS0703_DMA_RDLR		    0x0090
/* SDA建立时间设置寄存器 */
#define HS0703_SDA_SETUP        0x0094
/* General Call应答设置寄存器 */
#define HS0703_ACK_GENERAL_CALL 0x0098
/* I2C状态寄存器 */
#define HS0703_ENABLE_STATUS    0x009C
/* COMP参数 */
#define HS0703_COMP_PARAM_1     0x00F4
/* COMP版本 */
#define HS0703_COMP_VERSION     0x00F8

#define HS0703_SCL_HCNT         6
#define HS0703_SCL_LCNT         8
#define HS0703_RX_TX_CNT        63

#define BIT(nr)                 (1UL << (nr))
#define HS0703_INTR_MAX_NUM     (12)

#define HS0703_INTR_RX_UNDER    BIT(0)
#define HS0703_INTR_RX_OVER     BIT(1)
#define HS0703_INTR_RX_FULL     BIT(2)
#define HS0703_INTR_TX_OVER     BIT(3)
#define HS0703_INTR_TX_EMPTY    BIT(4)
#define HS0703_INTR_RD_REQ      BIT(5)
#define HS0703_INTR_TX_ABRT     BIT(6)
#define HS0703_INTR_RX_DONE     BIT(7)
#define HS0703_INTR_ACTIVITY    BIT(8)
#define HS0703_INTR_STOP_DET    BIT(9)
#define HS0703_INTR_START_DET   BIT(10)
#define HS0703_INTR_GEN_CALL    BIT(11)

typedef struct {
    uint32_t con;
    uint32_t tar;
    uint32_t sar;
    uint32_t hs_maddr;
    uint32_t data_cmd;
    uint32_t ss_scl_hcnt;
    uint32_t ss_scl_lcnt;
    uint32_t fs_scl_hcnt;
    uint32_t fs_scl_lcnt;
    uint32_t hs_scl_hcnt;
    uint32_t hs_scl_lcnt;
    uint32_t intr_stat;
    uint32_t intr_mask;
    uint32_t raw_intr_stat;
    uint32_t rx_tl;
    uint32_t tx_tl;
    uint32_t clr_intr;
    uint32_t clr_rx_under;
    uint32_t clr_rx_over;
    uint32_t clr_tx_over;
    uint32_t clr_rd_req;
    uint32_t clr_tx_abrt;
    uint32_t clr_rx_done;
    uint32_t clr_activity;
    uint32_t clr_stop_det;
    uint32_t clr_start_det;
    uint32_t clr_gen_call;
    uint32_t enable;
    uint32_t status;
    uint32_t txflr;
    uint32_t rxflr;
    uint32_t sda_hold;
    uint32_t tx_abrt_source;
    uint32_t slv_data_only;
    uint32_t dma_cr;
    uint32_t dma_tdlr;
    uint32_t dma_rdlr;
    uint32_t sda_setup;
    uint32_t ack_general_call;
    uint32_t enable_status;
    uint32_t comp_param_1;
    uint32_t comp_version;
} hs0703_regs;

typedef struct {
    SysBusDevice    parent_obj;
    MemoryRegion    iomem;
    qemu_irq        irq;

    I2CBus          *bus;

    bool            has_read;
    uint32_t        new_cmd_flag;
    uint8_t         slave_addr;

    /* I2C控制器寄存器列表 */
    hs0703_regs regs;

    // rx fifo ====
    struct {
        uint32_t    rcv_fifo_cnt;
        uint32_t    datafirst;
        uint32_t    datalast;
        Fifo8       recv_fifo;
    }rx;
} hs0703_state;


enum {
    A_NEW_TRANS = 0,
    CONTINU_TRANS,
    SEND_DATA,
    READ_DATA,
};


static const VMStateDescription vmstate_hs0703 = {
    .name = TYPE_HS0703_I2C,
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_END_OF_LIST()
    }
};


static void hs0703_upgrade_intr(hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;
    int trigger = 0;

    for (uint32_t i = 0; i < HS0703_INTR_MAX_NUM; i++) {
        uint8_t irqStatus = (regs->raw_intr_stat >> i) & 0x01;
        uint8_t irqMask = (regs->intr_mask >> i) & 0x01;
        if (irqStatus & irqMask) {
            regs->intr_stat |= BIT(i);
            trigger = 1;
        } else {
            regs->intr_stat &= ~BIT(i);
        }
    }

    qemu_set_irq(s->irq, trigger);
}

static uint64_t hs0703_read_part0(hwaddr offset, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;
    uint32_t ret = 0;

    switch (offset) {
        case HS0703_CON:
            return regs->con;
        case HS0703_TAR:
            return regs->tar;
        case HS0703_SAR:
            return regs->sar;
        case HS0703_HS_MADDR:
            return regs->hs_maddr;
        case HS0703_DATA_CMD:
            if (!fifo8_is_empty(&s->rx.recv_fifo)) {
                ret = fifo8_pop(&s->rx.recv_fifo);
            } else {
                DPRINTF("i2c HS0703_INTR_RX_UNDER is triggering\n");
                regs->raw_intr_stat |= HS0703_INTR_RX_UNDER;
                hs0703_upgrade_intr(s);
            }
            regs->rxflr = fifo8_num_used(&s->rx.recv_fifo);
            if (regs->rxflr < regs->rx_tl) {
                DPRINTF("i2c HS0703_INTR_RX_FULL is not triggering\n");
                regs->raw_intr_stat &= ~HS0703_INTR_RX_FULL;
                hs0703_upgrade_intr(s);
            }
            break;
        case HS0703_SS_SCL_HCNT:
            return regs->ss_scl_hcnt;
        case HS0703_SS_SCL_LCNT:
            return regs->ss_scl_lcnt;
        case HS0703_FS_SCL_HCNT:
            return regs->fs_scl_hcnt;
        case HS0703_FS_SCL_LCNT:
            return regs->fs_scl_lcnt;
        case HS0703_HS_SCL_HCNT:
            return regs->hs_scl_hcnt;
        default:
            return -1;
    }
    return ret;
}

static uint64_t hs0703_read_part1(hwaddr offset, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;
    uint32_t ret = 0;

    switch (offset) {
        case HS0703_HS_SCL_LCNT:
            return regs->hs_scl_lcnt;
        case HS0703_INTR_STAT:
            return regs->intr_stat;
        case HS0703_INTR_MASK:
            return regs->intr_mask;
        case HS0703_RAW_INTR_STAT:
            return regs->raw_intr_stat;
        case HS0703_RX_TL:
            return regs->rx_tl;
        case HS0703_TX_TL:
            return regs->tx_tl;
        case HS0703_CLR_INTR:
            regs->raw_intr_stat = 0;
            regs->tx_abrt_source = 0;
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_RX_UNDER:
            regs->raw_intr_stat &= ~(HS0703_INTR_RX_UNDER);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_RX_OVER:
            regs->raw_intr_stat &= ~(HS0703_INTR_RX_OVER);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_TX_OVER:
            regs->raw_intr_stat &= ~(HS0703_INTR_TX_OVER);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_RD_REQ:
            regs->raw_intr_stat &= ~(HS0703_INTR_RD_REQ);
            hs0703_upgrade_intr(s);
            break;
        default:
            return -1;
    }
    return ret;
}

static uint64_t hs0703_read_part2(hwaddr offset, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;
    uint32_t ret = 0;

    switch (offset) {
        case HS0703_CLR_TX_ABRT:
            regs->raw_intr_stat &= ~(HS0703_INTR_TX_ABRT);
            regs->tx_abrt_source = 0;
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_RX_DONE:
            regs->raw_intr_stat &= ~(HS0703_INTR_RX_DONE);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_ACTIVITY:
            regs->raw_intr_stat &= ~(HS0703_INTR_ACTIVITY);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_STOP_DET:
            regs->raw_intr_stat &= ~(HS0703_INTR_STOP_DET);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_START_DET:
            regs->raw_intr_stat &= ~(HS0703_INTR_START_DET);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_CLR_GEN_CALL:
            regs->raw_intr_stat &= ~(HS0703_INTR_GEN_CALL);
            hs0703_upgrade_intr(s);
            break;
        case HS0703_ENABLE:
            return regs->enable;
        case HS0703_STATUS:
            regs->status = 0;
            if ((regs->txflr > 0) || (regs->rxflr > 0)) {
                regs->status |= BIT(5);
                regs->status |= BIT(0);
            }
            regs->status |= (regs->txflr >= RECV_FIFO_LENGTH ? 0x00 : BIT(1));
            regs->status |= (regs->txflr != 0 ? 0x00 : BIT(2));
            regs->status |= (fifo8_is_empty(&s->rx.recv_fifo) == true ? 0x00 : BIT(3));
            regs->status |= (fifo8_is_full(&s->rx.recv_fifo) == false ? 0x00 : BIT(4));
            ret = regs->status;
            break;
        default:
            return -1;
    }
    return ret;
}

static uint64_t hs0703_read_part3(hwaddr offset, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;
    uint32_t ret = 0;

    switch (offset) {
        case HS0703_TXFLR:
            return regs->txflr;
        case HS0703_RXFLR:
            return regs->rxflr;
        case HS0703_SDA_HOLD:
            return regs->sda_hold;
        case HS0703_TX_ABRT_SOURCE:
            return regs->tx_abrt_source;
        case HS0703_SLV_DATA_ONLY:
            return regs->slv_data_only;
        case HS0703_DMA_CR:
            return regs->dma_cr;
        case HS0703_DMA_TDLR:
            return regs->dma_tdlr;
        case HS0703_DMA_RDLR:
            return regs->dma_rdlr;
        case HS0703_SDA_SETUP:
            return regs->sda_setup;
        case HS0703_ACK_GENERAL_CALL:
            return regs->ack_general_call;
        case HS0703_ENABLE_STATUS:
            regs->enable_status |= BIT(2);
            if (regs->enable == 1) {
                regs->enable_status |= BIT(0);
            } else {
                regs->enable_status &= ~BIT(2);
            }
            return regs->enable_status;
        case HS0703_COMP_PARAM_1:
            return regs->comp_param_1;
        case HS0703_COMP_VERSION:
            return regs->comp_version;
        default:
            return -1;
    }
    return ret;
}

static uint64_t hs0703_read(void *opaque, hwaddr offset, unsigned size)
{
    hs0703_state *s = (hs0703_state *)opaque;
    uint32_t ret = 0;

    if ((offset >= HS0703_CON) && (offset <= HS0703_HS_SCL_HCNT)) {
        ret =  hs0703_read_part0(offset, s);
    } else if ((offset >= HS0703_HS_SCL_LCNT) && (offset <= HS0703_CLR_RD_REQ)) {
        ret =  hs0703_read_part1(offset, s);
    }  else if ((offset >= HS0703_CLR_TX_ABRT) && (offset <= HS0703_STATUS)) {
        ret =  hs0703_read_part2(offset, s);
    }  else if ((offset >= HS0703_TXFLR) && (offset <= HS0703_COMP_VERSION)) {
        ret =  hs0703_read_part3(offset, s);
    }  else {
        ret = -1;
    }

    DPRINTF("[i2c read reg]:0x%lx [offset:0x%x data:0x%x]\n", (uint64_t)opaque, (uint32_t)offset, (uint32_t)ret);
    return ret;
}

static void hs0703_transfer(hs0703_state *s, uint32_t data)
{
    hs0703_regs *regs = &s->regs;

    if (s->new_cmd_flag == A_NEW_TRANS) {
        const int is_read = I2C_IS_READ(data);
        i2c_start_transfer(s->bus, (uint8_t)s->slave_addr, is_read);
        DPRINTF("i2c send dev 0x%x reg 0x%x\n", s->slave_addr, data);
        i2c_send(s->bus, (uint8_t)data);
        s->new_cmd_flag = CONTINU_TRANS;
    } else if (I2C_IS_READ(data)) {
        if (s->new_cmd_flag == CONTINU_TRANS) {
            i2c_start_transfer(s->bus, (uint8_t)s->slave_addr, true);
            s->new_cmd_flag = READ_DATA;
        }
        uint8_t temp = i2c_recv(s->bus);
        DPRINTF("i2c recv:0x%x\n", temp);
        if (!fifo8_is_full(&s->rx.recv_fifo)) {
            fifo8_push(&s->rx.recv_fifo, temp);
            regs->rxflr = fifo8_num_used(&s->rx.recv_fifo);
            if (regs->rxflr >= regs->rx_tl) {
                regs->raw_intr_stat |= HS0703_INTR_RX_FULL;
                hs0703_upgrade_intr(s);
            }
            s->has_read = true;
        } else {
            regs->raw_intr_stat |= HS0703_INTR_RX_OVER;
            hs0703_upgrade_intr(s);
            return;
        }
        s->has_read = true;
    } else {
        s->new_cmd_flag = SEND_DATA;
        DPRINTF("i2c send data 0x%x \n", data);
        i2c_send(s->bus, (uint8_t)data);
    }

    if (I2C_NEED_STOP(data)) {
        if (s->has_read) {
            i2c_nack(s->bus);
            s->has_read = false;
        }
        DPRINTF("i2c end \n");
        i2c_end_transfer(s->bus);
        s->new_cmd_flag = A_NEW_TRANS;
        regs->raw_intr_stat &= ~HS0703_INTR_TX_EMPTY;
        regs->raw_intr_stat |= HS0703_INTR_STOP_DET;
        hs0703_upgrade_intr(s);
    } else {
        regs->raw_intr_stat |= HS0703_INTR_TX_EMPTY;
        hs0703_upgrade_intr(s);
    }
}

static void hs0703_write_part0(hwaddr offset, uint64_t val, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;

    switch (offset) {
        case HS0703_CON:
            HS0703_DISABLE_SET_REG(regs->enable, regs->con, (uint32_t)val & 0x7f);
            break;
        case HS0703_TAR:
            HS0703_DISABLE_SET_REG(regs->enable, regs->tar, (uint32_t)val & 0x1fff);
            /* 先不考虑10bit的从设备地址 */
            s->slave_addr = (uint8_t)val & 0x7f;
            break;
        case HS0703_SAR:
            HS0703_DISABLE_SET_REG(regs->enable, regs->sar, (uint32_t)val & 0x3ff);
            break;
        case HS0703_HS_MADDR:
            HS0703_DISABLE_SET_REG(regs->enable, regs->hs_maddr, (uint32_t)val & 0x7);
            break;
        case HS0703_DATA_CMD:
            hs0703_transfer(s, (uint32_t)val);
            break;
        case HS0703_SS_SCL_HCNT:
            val = (val < HS0703_SCL_HCNT ? HS0703_SCL_HCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->ss_scl_hcnt, (uint32_t)val & 0xffff);
            break;
        case HS0703_SS_SCL_LCNT:
            val = (val < HS0703_SCL_LCNT ? HS0703_SCL_LCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->ss_scl_lcnt, (uint32_t)val & 0xffff);
            break;
        case HS0703_FS_SCL_HCNT:
            val = (val < HS0703_SCL_HCNT ? HS0703_SCL_HCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->fs_scl_hcnt, (uint32_t)val & 0xffff);
            break;
        case HS0703_FS_SCL_LCNT:
            val = (val < HS0703_SCL_LCNT ? HS0703_SCL_LCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->fs_scl_lcnt, (uint32_t)val & 0xffff);
            break;
        case HS0703_HS_SCL_HCNT:
            val = (val < HS0703_SCL_HCNT ? HS0703_SCL_HCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->hs_scl_hcnt, (uint32_t)val & 0xffff);
            break;
        default:
            break;
    }
}

static void hs0703_write_part1(hwaddr offset, uint64_t val, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;

    switch (offset) {
        case HS0703_HS_SCL_LCNT:
            val = (val < HS0703_SCL_LCNT ? HS0703_SCL_LCNT : val);
            HS0703_DISABLE_SET_REG(regs->enable, regs->hs_scl_lcnt, (uint32_t)val & 0xffff);
            break;
        case HS0703_INTR_STAT:
            break;
        case HS0703_INTR_MASK:
            regs->intr_mask = (uint32_t)val & 0xfff;
            hs0703_upgrade_intr(s);
            break;
        case HS0703_RAW_INTR_STAT:
            break;
        case HS0703_RX_TL:
            val = (val < HS0703_RX_TX_CNT ? val + 1 : HS0703_RX_TX_CNT);
            regs->rx_tl = (uint32_t)val & 0xff;
            break;
        case HS0703_TX_TL:
            val = (val < HS0703_RX_TX_CNT ? val + 1 : HS0703_RX_TX_CNT);
            regs->tx_tl = (uint32_t)val & 0xff;
            break;
        case HS0703_CLR_INTR:
            break;
        case HS0703_CLR_RX_UNDER:
            break;
        case HS0703_CLR_RX_OVER:
            break;
        case HS0703_CLR_TX_OVER:
            break;
        case HS0703_CLR_RD_REQ:
            break;
        default:
            break;
    }
}

static void hs0703_write_part2(hwaddr offset, uint64_t val, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;

    switch (offset) {
        case HS0703_CLR_TX_ABRT:
            break;
        case HS0703_CLR_RX_DONE:
            break;
        case HS0703_CLR_ACTIVITY:
            break;
        case HS0703_CLR_STOP_DET:
            break;
        case HS0703_CLR_START_DET:
            break;
        case HS0703_CLR_GEN_CALL:
            break;
        case HS0703_ENABLE:
            if ((val & 0x1) == 0) {
                fifo8_reset(&s->rx.recv_fifo);
                regs->txflr = 0;
                regs->rxflr = 0;
            } else {
                DPRINTF("i2c HS0703_INTR_ACTIVITY is triggering\n");
                regs->raw_intr_stat |= HS0703_INTR_TX_EMPTY;
                regs->raw_intr_stat |= HS0703_INTR_ACTIVITY;
                hs0703_upgrade_intr(s);
            }
            regs->enable = val & 0x1;
            break;
        case HS0703_STATUS:
            break;
        default:
            break;
    }
}

static void hs0703_write_part3(hwaddr offset, uint64_t val, hs0703_state *s)
{
    hs0703_regs *regs = &s->regs;

    switch (offset) {
        case HS0703_TXFLR:
            break;
        case HS0703_RXFLR:
            break;
        case HS0703_SDA_HOLD:
            HS0703_DISABLE_SET_REG(regs->enable, regs->sda_hold, (uint32_t)val & 0xffff);
            break;
        case HS0703_TX_ABRT_SOURCE:
            break;
        case HS0703_SLV_DATA_ONLY:
            regs->slv_data_only = (uint32_t)val & 0x1;
            break;
        case HS0703_DMA_CR:
            regs->dma_cr = (uint32_t)val & 0x3;
            break;
        case HS0703_DMA_TDLR:
            regs->dma_tdlr = (uint32_t)val & 0xf;
            break;
        case HS0703_DMA_RDLR:
            regs->dma_rdlr = (uint32_t)val & 0xf;
            break;
        case HS0703_SDA_SETUP:
            regs->sda_setup = (uint32_t)val & 0xff;
            break;
        case HS0703_ACK_GENERAL_CALL:
            regs->ack_general_call = (uint32_t)val & 0x1;
            break;
        case HS0703_ENABLE_STATUS:
            break;
        case HS0703_COMP_PARAM_1:
            break;
        case HS0703_COMP_VERSION:
            break;
        default:
            break;
    }
}

static void hs0703_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
{
    hs0703_state *s = (hs0703_state *)opaque;
    DPRINTF("[i2c write reg]:0x%lx [offset:0x%x data:0x%x]\n", (uint64_t)opaque, (uint32_t)offset, (uint32_t)val);

    if ((offset >= HS0703_CON) && (offset <= HS0703_HS_SCL_HCNT)) {
        hs0703_write_part0(offset, val, s);
    } else if ((offset >= HS0703_HS_SCL_LCNT) && (offset <= HS0703_CLR_RD_REQ)) {
        hs0703_write_part1(offset, val, s);
    }  else if ((offset >= HS0703_CLR_TX_ABRT) && (offset <= HS0703_STATUS)) {
        hs0703_write_part2(offset, val, s);
    }  else if ((offset >= HS0703_TXFLR) && (offset <= HS0703_COMP_VERSION)) {
        hs0703_write_part3(offset, val, s);
    } else {
        DPRINTF("[i2c write reg]:offset:0x%x is false\n", offset);
    }
}

static const MemoryRegionOps hs0703_ops = {
    .read = hs0703_read,
    .write = hs0703_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

static void hs0703_reset(DeviceState *d)
{
    hs0703_state *s = HS0703(OBJECT(d));
    hs0703_regs *regs = &s->regs;
    fifo8_reset(&s->rx.recv_fifo);
    s->new_cmd_flag = A_NEW_TRANS;
    regs->txflr = 0;
    regs->rxflr = 0;
}

static void hs0703_init(Object *obj)
{
    DeviceState *dev = DEVICE(obj);
    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
    hs0703_state *s = HS0703(obj);

    s->rx.datafirst = 0;
    s->rx.datalast = 0;
    s->has_read = false;
    s->bus = i2c_init_bus(dev, "i2c");

    s->new_cmd_flag = A_NEW_TRANS;

    hs0703_regs *regs = &(s->regs);
    memset(regs, 0, sizeof(hs0703_regs));
    regs->con = 0x67;
    regs->tar = 0x55;
    regs->sar = 0x55;
    regs->hs_maddr = 0x1;
    regs->ss_scl_hcnt = 0x190;
    regs->ss_scl_lcnt = 0x1D6;
    regs->fs_scl_hcnt = 0x3C;
    regs->fs_scl_lcnt = 0x82;
    regs->hs_scl_hcnt = 0x6;
    regs->hs_scl_lcnt = 0x10;
    regs->intr_mask = 0x8FF;
    regs->rx_tl = 0x3;
    regs->tx_tl = 0x3;
    regs->status = 0x6;
    regs->sda_hold = 0x1;
    regs->sda_setup = 0x64;
    regs->ack_general_call = 0x1;
    regs->comp_param_1 = 0x003F3FEA;
    regs->comp_version = 0x3230312A;

    memory_region_init_io(&s->iomem, OBJECT(dev), &hs0703_ops, s, TYPE_HS0703_I2C, 0x1000);
    sysbus_init_mmio(sd, &s->iomem);
    sysbus_init_irq(sd, &s->irq);

    fifo8_create(&s->rx.recv_fifo, RECV_FIFO_LENGTH);
}

static void hs0703_realize(DeviceState *d, Error **errp)
{
}

static void hs0703_finalize(Object *obj)
{
}

static Property hs0703_properties[] = {
    DEFINE_PROP_END_OF_LIST(),
};

static void hs0703_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->realize = hs0703_realize;
    dc->reset = hs0703_reset;
    dc->vmsd = &vmstate_hs0703;
    device_class_set_props(dc, hs0703_properties);
}

static const TypeInfo hs0703_info = {
    .name          = TYPE_HS0703_I2C,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(hs0703_state),
    .instance_init = hs0703_init,
    .instance_finalize = hs0703_finalize,
    .class_init    = hs0703_class_init,
};

static void hs0703_register_types(void)
{
    type_register_static(&hs0703_info);
}

type_init(hs0703_register_types)
